"""
可迭代对象需具有__iter__(),可以使用isinstance()来判断是否是可迭代对象

"""
from collections.abc import Iterable
print(isinstance('abc', Iterable))


print('\n---------------------------------------------\n')
# 生成自己的迭代器
class MyIterator:
    def __init__(self):
        self.n = '生死之间'
        self.i = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.i >= len(self.n):
            raise StopIteration
        else:
            ch = self.n[self.i]
            self.i += 1
            return ch
mi = iter(MyIterator())
for x in mi:
    print(x)

print('\n---------------------------------------------\n')

# 生成器
def reverse(data):
    for index in range(len(data) - 1, -1, -1):
        yield data[index]

for char in reverse("Hello"):
    print(char)

# 生成一个list,但不是一下就生成
gen = (x ** 2 for x in range(5))
for g in gen:
    print(g)

print('\n-----------------------闭包与装饰器----------------------\n')
"""
 闭包：
     又称词法闭包（Lexical Closure）或函数闭包（function closures），是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在，即使已经离开了创造它的环境也不例外。
     所以，有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例，不同的引用环境和相同的函数组合可以产生不同的实例。
    通过下面的示例，我们会发现闭包与类有一些相似，比如：它们都能实现数据的封装、方法的复用等；此外，通过使用闭包可以避免使用全局变量，还能将函数与其所操作的数据关连起来。
"""
def x(id):
    def y(name):
        print ('id:', id, 'name:', name)
    return y

y = x('ityard')
y('程序之间')

print('\n-----------------------装饰器----------------------\n')
"""
    装饰器（decorator）也称装饰函数，是一种闭包的应用，其主要是用于某些函数需要拓展功能，但又不希望修改原函数，它就是语法糖，使用它可以简化代码、增强其可读性，
    当然装饰器不是必须要求被使用的，不使用也是可以的，Python 中装饰器通过 @ 符号来进行标识。

    装饰器可以基于函数实现也可基于类实现，其使用方式基本是固定的，看一下基本步骤：
    
    定义装饰函数（类）
    定义业务函数
    在业务函数上添加 @装饰函数（类）名
"""

# 基于函数
# 装饰函数
def funA(fun):
    def funB(*args, **kw):
        print('函数 ' + fun.__name__ + ' 开始执行')
        fun(*args, **kw)
        print('函数 ' + fun.__name__ + ' 执行完成')
    return funB

@funA
# 业务函数
def funC(name):
  print('Hello', name)

funC('Jhon')

print('\n---------------------------------------------\n')
# 装饰函数
def funA(flag):
    def funB(fun):
        def funC(*args, **kw):
            if flag == True:
                print('==========')
            elif flag == False:
                print('----------')
            fun(*args, **kw)
        return funC
    return funB

@funA(False)
# 业务函数
def funD(name):
  print('Hello', name)

funD('Jhon')

# 等价于下面这个
# funA(False)(funD)('John')

# 基于类
print('\n----------------------基于类----------------------\n')
class Test(object):
    def __init__(self, func):
        print('函数名是 %s ' % func.__name__)
        self.__func = func

    def __call__(self, *args, **kwargs):
        self.__func(args[0], kwargs['age'])


@Test
def hello(name, age=22):
    print('Hello ... %s, your age is %d' % (name, age))


hello("yeskip", age=23)

"""
    总结感悟：
        python中的装饰器有点类似于java中的切面，对被装饰函数的一种修饰。
        其底层实现原理就是：闭包。
        闭包就是： 私有的环境 + 函数
        通过特定实际触发闭包就可以实现装饰器的功能。
"""

print('\n----------------------练习闭包----------------------\n')

# 装饰函数
def methodA(isSuccess):
    # 装饰函数，参数是被装饰函数
    def aa(func):
        # 包装函数，参数是被装饰函数的参数
        def funcA(*args, **kwargs):
            print("准备连接....")
            if isSuccess:
                func(*args, **kwargs)
                print('执行成功了，不用回滚，直接提交。')
            else:
                func(*args, **kwargs)
                print('执行失败了，需要回滚操作了！')
        return funcA
    # 返回装饰函数
    return aa

@methodA(False)
def methodB(a, id=101):
    print("id=%d连接数据库，执行修改记录: %s操作～" % (id,a))

methodB(1000, 103)
